package eu.catengine.scene;

import java.util.ArrayList;
import java.util.HashMap;

import javax.microedition.khronos.opengles.GL10;

import eu.catengine.primitive.Point;
import eu.catengine.renderable.Renderable;

// dodawanie, wyszukiwanie, usuwanie
// warstw oraz obiektow

/**
 * Klasa służąca jako korzeń drzewa obiektów przechowywanych w scenie.
 * 
 * @author mbienkowski
 */
public class LayerTree extends Layer
{
    protected ArrayList<Layer> mTreeLayerList;
    protected ArrayList<Renderable> mTreeUpdateList;
    protected ArrayList<Renderable> mTreeRenderList;

    protected HashMap<String, Renderable> mTreeObjectMap;
    protected HashMap<String, Layer> mTreeObjectLayerMap;
    protected HashMap<String, Layer> mTreeLayerMap;

    protected Scene mParentScene;

    protected LayerTree(Scene scene, String name)
    {
	super(name, null, null);

	mRoot = this;

	mTreeLayerList = new ArrayList<Layer>();
	mTreeLayerMap = new HashMap<String, Layer>();

	mTreeUpdateList = new ArrayList<Renderable>();
	mTreeObjectMap = new HashMap<String, Renderable>();
	mTreeObjectLayerMap = new HashMap<String, Layer>();
	mTreeRenderList = new ArrayList<Renderable>();

	mParentScene = scene;
    }

    /**
     * Atualizuje listę obiektów do renderowania.<br>
     * <b>Wywołuje się automatycznie.</b> <br>
     * Nie należy wywoływać metody ręcznie.
     */
    protected void updateRenderList()
    {
	mTreeRenderList = this.getAllObjectDFS();
    }

    /**
     * Aktualizuje elementy, których flaga "updateNeeded" ustawiona jest na
     * true.<br>
     * <b>Wywołuje się automatycznie.</b><br>
     * Nie należy wywoływać metody ręcznie.
     */
    public void updateObjects(long elapsedTime)
    {
	for (int i = 0; i < mTreeUpdateList.size(); i++)
	{
	    mTreeUpdateList.get(i).update(elapsedTime);

	    if (!mTreeUpdateList.get(i).getKeepInScene())
	    {
		deleteObject(mTreeUpdateList.get(i));
		i--;
	    }
	}
    }

    /**
     * Renderuje wszystkie obiekty zawarate w drzewie. <br>
     * <b>Wywołuje się automatycznie.</b><br>
     * Nie należy wywoływać metody ręcznie.
     */
    public void renderObjects(GL10 gl)
    {
	for (int i = 0; i < mTreeRenderList.size(); i++)
	{
	    mTreeRenderList.get(i).draw(gl);
	}
    }

    /**
     * Zwraca element który występuje w danym punkcie i jednocześnie jest
     * najwyżej w warstwie sceny.
     * 
     * @param point
     *            <code>Point</code> Punkt poszukiwań obiektu.
     * @return <code>Renderable</code> Odnaleziony element lub null w przypadku braku
     *         elementu.
     */
    public Renderable getObjectAtPoint(Point point)
    {
	for (int i = mTreeRenderList.size() - 1; i >= 0; i--)
	{
	    if (mTreeRenderList.get(i).isAtPoint(point))
	    {
		return mTreeRenderList.get(i);
	    }
	}

	return null;
    }
    
    /**
     * Usuwa warstwę o nazwie podanej jako parametr.
     */
    public void deleteLayer(String name)
    {
	try
	{
	    mTreeLayerMap.get(name).deleteLayer();
	}
	catch(Exception e)
	{
	    e.printStackTrace();
	}
    }

    /**
     * Zwraca wszystkie elementy znajdujące się w danym punkcie.
     * 
     * @param point
     *            <code>Point</code> Punkt poszukiwań obiektów.
     * @return <code>ArrayList<Renderable></code> Lista znalezionych obiektów.
     */
    public ArrayList<Renderable> getObjectsAtPoint(Point point)
    {
	ArrayList<Renderable> list = new ArrayList<Renderable>();

	for (int i = mTreeRenderList.size() - 1; i >= 0; i--)
	{
	    if (mTreeRenderList.get(i).isAtPoint(point))
	    {
		list.add(mTreeRenderList.get(i));
	    }
	}

	return list;
    }

    @Override
    public void dispose()
    {
	super.dispose();

	mTreeLayerList.clear();
	mTreeUpdateList.clear();
	mTreeRenderList.clear();
	mTreeObjectMap.clear();
	mTreeObjectLayerMap.clear();
	mTreeLayerMap.clear();

	mTreeLayerList = null;
	mTreeUpdateList = null;
	mTreeRenderList = null;
	mTreeObjectMap = null;
	mTreeObjectLayerMap = null;
	mTreeLayerMap = null;
	mParentScene = null;
    }

}
